home *** CD-ROM | disk | FTP | other *** search
/ Revista do CD-ROM 151 / cd-rom 151.iso / internet / firefox / Firefox Setup 3.0 Beta 1.exe / nonlocalized / components / WebContentConverter.js < prev   
Encoding:
Text File  |  2007-11-09  |  32.4 KB  |  981 lines

  1. //@line 38 "e:\builds\tinderbox\Fx-Rel\WINNT_5.2_Depend\mozilla\browser\components\feeds\src\WebContentConverter.js"
  2.  
  3. const Cc = Components.classes;
  4. const Ci = Components.interfaces;
  5. const Cr = Components.results;
  6.  
  7. function LOG(str) {
  8.   dump("*** " + str + "\n");
  9. }
  10.  
  11. const WCCR_CONTRACTID = "@mozilla.org/embeddor.implemented/web-content-handler-registrar;1";
  12. const WCCR_CLASSID = Components.ID("{792a7e82-06a0-437c-af63-b2d12e808acc}");
  13. const WCCR_CLASSNAME = "Web Content Handler Registrar";
  14.  
  15. const WCC_CLASSID = Components.ID("{db7ebf28-cc40-415f-8a51-1b111851df1e}");
  16. const WCC_CLASSNAME = "Web Service Handler";
  17.  
  18. const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
  19. const TYPE_ANY = "*/*";
  20.  
  21. const PREF_CONTENTHANDLERS_AUTO = "browser.contentHandlers.auto.";
  22. const PREF_CONTENTHANDLERS_BRANCH = "browser.contentHandlers.types.";
  23. const PREF_SELECTED_WEB = "browser.feeds.handlers.webservice";
  24. const PREF_SELECTED_ACTION = "browser.feeds.handler";
  25. const PREF_SELECTED_READER = "browser.feeds.handler.default";
  26.  
  27. const STRING_BUNDLE_URI = "chrome://browser/locale/feeds/subscribe.properties";
  28.  
  29. const NS_ERROR_MODULE_DOM = 2152923136;
  30. const NS_ERROR_DOM_SYNTAX_ERR = NS_ERROR_MODULE_DOM + 12;
  31.  
  32. function WebContentConverter() {
  33. }
  34. WebContentConverter.prototype = {
  35.   convert: function WCC_convert() { },
  36.   asyncConvertData: function WCC_asyncConvertData() { },
  37.   onDataAvailable: function WCC_onDataAvailable() { },
  38.   onStopRequest: function WCC_onStopRequest() { },
  39.   
  40.   onStartRequest: function WCC_onStartRequest(request, context) {
  41.     var wccr = 
  42.         Cc[WCCR_CONTRACTID].
  43.         getService(Ci.nsIWebContentConverterService);
  44.     wccr.loadPreferredHandler(request);
  45.   },
  46.   
  47.   QueryInterface: function WCC_QueryInterface(iid) {
  48.     if (iid.equals(Ci.nsIStreamConverter) ||
  49.         iid.equals(Ci.nsIStreamListener) ||
  50.         iid.equals(Ci.nsISupports))
  51.       return this;
  52.     throw Cr.NS_ERROR_NO_INTERFACE;
  53.   }
  54. };
  55.  
  56. var WebContentConverterFactory = {
  57.   createInstance: function WCCF_createInstance(outer, iid) {
  58.     if (outer != null)
  59.       throw Cr.NS_ERROR_NO_AGGREGATION;
  60.     return new WebContentConverter().QueryInterface(iid);
  61.   },
  62.     
  63.   QueryInterface: function WCC_QueryInterface(iid) {
  64.     if (iid.equals(Ci.nsIFactory) ||
  65.         iid.equals(Ci.nsISupports))
  66.       return this;
  67.     throw Cr.NS_ERROR_NO_INTERFACE;
  68.   }
  69. };
  70.  
  71. function ServiceInfo(contentType, uri, name) {
  72.   this._contentType = contentType;
  73.   this._uri = uri;
  74.   this._name = name;
  75. }
  76. ServiceInfo.prototype = {
  77.   /**
  78.    * See nsIHandlerApp
  79.    */
  80.   get name() {
  81.     return this._name;
  82.   },
  83.   
  84.   /**
  85.    * See nsIHandlerApp
  86.    */
  87.   equals: function SI_equals(aHandlerApp) {
  88.     if (!aHandlerApp)
  89.       throw Cr.NS_ERROR_NULL_POINTER;
  90.  
  91.     if (aHandlerApp instanceof Ci.nsIWebContentHandlerInfo &&
  92.         aHandlerApp.contentType == this.contentType &&
  93.         aHandlerApp.uri == this.uri)
  94.       return true;
  95.  
  96.     return false;
  97.   },
  98.  
  99.   /**
  100.    * See nsIWebContentHandlerInfo
  101.    */
  102.   get contentType() {
  103.     return this._contentType;
  104.   },
  105.  
  106.   /**
  107.    * See nsIWebContentHandlerInfo
  108.    */
  109.   get uri() {
  110.     return this._uri;
  111.   },
  112.  
  113.   /**
  114.    * See nsIWebContentHandlerInfo
  115.    */
  116.   getHandlerURI: function SI_getHandlerURI(uri) {
  117.     return this._uri.replace(/%s/gi, encodeURIComponent(uri));
  118.   },
  119.   
  120.   QueryInterface: function SI_QueryInterface(iid) {
  121.     if (iid.equals(Ci.nsIWebContentHandlerInfo) ||
  122.         iid.equals(Ci.nsISupports))
  123.       return this;
  124.     throw Cr.NS_ERROR_NO_INTERFACE;
  125.   }
  126. };
  127.  
  128. var WebContentConverterRegistrar = {
  129.   _stringBundle: null,
  130.  
  131.   get stringBundle() {
  132.     if (!this._stringBundle) {
  133.       this._stringBundle = Cc["@mozilla.org/intl/stringbundle;1"].
  134.                             getService(Ci.nsIStringBundleService).
  135.                             createBundle(STRING_BUNDLE_URI);
  136.     }
  137.  
  138.     return this._stringBundle;
  139.   },
  140.  
  141.   _getFormattedString: function WCCR__getFormattedString(key, params) {
  142.     return this.stringBundle.formatStringFromName(key, params, params.length);
  143.   },
  144.   
  145.   _getString: function WCCR_getString(key) {
  146.     return this.stringBundle.GetStringFromName(key);
  147.   },
  148.  
  149.   _contentTypes: { },
  150.  
  151.   /**
  152.    * Track auto handlers for various content types using a content-type to 
  153.    * handler map.
  154.    */
  155.   _autoHandleContentTypes: { },
  156.  
  157.   /**
  158.    * See nsIWebContentConverterService
  159.    */
  160.   getAutoHandler: 
  161.   function WCCR_getAutoHandler(contentType) {
  162.     contentType = this._resolveContentType(contentType);
  163.     if (contentType in this._autoHandleContentTypes)
  164.       return this._autoHandleContentTypes[contentType];
  165.     return null;
  166.   },
  167.   
  168.   /**
  169.    * See nsIWebContentConverterService
  170.    */
  171.   setAutoHandler:
  172.   function WCCR_setAutoHandler(contentType, handler) {
  173.     if (handler && !this._typeIsRegistered(contentType, handler.uri))
  174.       throw Cr.NS_ERROR_NOT_AVAILABLE;
  175.       
  176.     contentType = this._resolveContentType(contentType);
  177.     this._setAutoHandler(contentType, handler);
  178.     
  179.     var ps = 
  180.         Cc["@mozilla.org/preferences-service;1"].
  181.         getService(Ci.nsIPrefService);
  182.     var autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO);
  183.     if (handler)
  184.       autoBranch.setCharPref(contentType, handler.uri);
  185.     else if (autoBranch.prefHasUserValue(contentType))
  186.       autoBranch.clearUserPref(contentType);
  187.      
  188.     ps.savePrefFile(null);
  189.   },
  190.   
  191.   /**
  192.    * Update the internal data structure (not persistent)
  193.    */
  194.   _setAutoHandler:
  195.   function WCCR__setAutoHandler(contentType, handler) {
  196.     if (handler) 
  197.       this._autoHandleContentTypes[contentType] = handler;
  198.     else if (contentType in this._autoHandleContentTypes)
  199.       delete this._autoHandleContentTypes[contentType];
  200.   },
  201.   
  202.   /**
  203.    * See nsIWebContentConverterService
  204.    */
  205.   getWebContentHandlerByURI:
  206.   function WCCR_getWebContentHandlerByURI(contentType, uri) {
  207.     var handlers = this.getContentHandlers(contentType, { });
  208.     for (var i = 0; i < handlers.length; ++i) {
  209.       if (handlers[i].uri == uri) 
  210.         return handlers[i];
  211.     }
  212.     return null;
  213.   },
  214.   
  215.   /**
  216.    * See nsIWebContentConverterService
  217.    */
  218.   loadPreferredHandler: 
  219.   function WCCR_loadPreferredHandler(request) {
  220.     var channel = request.QueryInterface(Ci.nsIChannel);
  221.     var contentType = this._resolveContentType(channel.contentType);
  222.     var handler = this.getAutoHandler(contentType);
  223.     if (handler) {
  224.       request.cancel(Cr.NS_ERROR_FAILURE);
  225.       
  226.       var webNavigation = 
  227.           channel.notificationCallbacks.getInterface(Ci.nsIWebNavigation);
  228.       webNavigation.loadURI(handler.getHandlerURI(channel.URI.spec), 
  229.                             Ci.nsIWebNavigation.LOAD_FLAGS_NONE, 
  230.                             null, null, null);
  231.     }      
  232.   },
  233.   
  234.   /**
  235.    * See nsIWebContentConverterService
  236.    */
  237.   removeProtocolHandler: 
  238.   function WCCR_removeProtocolHandler(aProtocol, aURITemplate) {
  239.     var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
  240.               getService(Ci.nsIExternalProtocolService);
  241.     var handlerInfo = eps.getProtocolHandlerInfo(aProtocol);
  242.     var handlers =  handlerInfo.possibleApplicationHandlers;
  243.     for (let i = 0; i < handlers.length; i++) {
  244.       try { // We only want to test web handlers
  245.         let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
  246.         if (handler.uriTemplate == aURITemplate) {
  247.           handlers.removeElementAt(i);
  248.           var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
  249.                    getService(Ci.nsIHandlerService);
  250.           hs.store(handlerInfo);
  251.           return;
  252.         }
  253.       } catch (e) { /* it wasn't a web handler */ }
  254.     }
  255.   },
  256.   
  257.   /**
  258.    * See nsIWebContentConverterService
  259.    */
  260.   removeContentHandler: 
  261.   function WCCR_removeContentHandler(contentType, uri) {
  262.     function notURI(serviceInfo) {
  263.       return serviceInfo.uri != uri;
  264.     }
  265.   
  266.     if (contentType in this._contentTypes) {
  267.       this._contentTypes[contentType] = 
  268.         this._contentTypes[contentType].filter(notURI);
  269.     }
  270.   },
  271.   
  272.   /**
  273.    *
  274.    */
  275.   _mappings: { 
  276.     "application/rss+xml": TYPE_MAYBE_FEED,
  277.     "application/atom+xml": TYPE_MAYBE_FEED,
  278.   },
  279.   
  280.   /**
  281.    * These are types for which there is a separate content converter aside 
  282.    * from our built in generic one. We should not automatically register
  283.    * a factory for creating a converter for these types.
  284.    */
  285.   _blockedTypes: {
  286.     "application/vnd.mozilla.maybe.feed": true,
  287.   },
  288.   
  289.   /**
  290.    * Determines the "internal" content type based on the _mappings.
  291.    * @param   contentType
  292.    * @returns The resolved contentType value. 
  293.    */
  294.   _resolveContentType: 
  295.   function WCCR__resolveContentType(contentType) {
  296.     if (contentType in this._mappings)
  297.       return this._mappings[contentType];
  298.     return contentType;
  299.   },
  300.  
  301.   _makeURI: function(aURL, aOriginCharset, aBaseURI) {
  302.     var ioService = Components.classes["@mozilla.org/network/io-service;1"]
  303.                               .getService(Components.interfaces.nsIIOService);
  304.     return ioService.newURI(aURL, aOriginCharset, aBaseURI);
  305.   },
  306.  
  307.   _checkAndGetURI:
  308.   function WCCR_checkAndGetURI(aURIString)
  309.   {
  310.     try {
  311.       var uri = this._makeURI(aURIString);
  312.     } catch (ex) {
  313.       // not supposed to throw according to spec
  314.       return; 
  315.     }
  316.  
  317.     // If the uri doesn't contain '%s', it won't be a good handler
  318.     if (uri.spec.indexOf("%s") < 0)
  319.       throw NS_ERROR_DOM_SYNTAX_ERR; 
  320.  
  321.     return uri;
  322.   },
  323.  
  324.   /**
  325.    * Determines if a web handler is already registered.
  326.    *
  327.    * @param aProtocol
  328.    *        The scheme of the web handler we are checking for.
  329.    * @param aURITemplate
  330.    *        The URI template that the handler uses to handle the protocol.
  331.    * @return true if it is already registered, false otherwise.
  332.    */
  333.   _protocolHandlerRegistered:
  334.   function WCCR_protocolHandlerRegistered(aProtocol, aURITemplate) {
  335.     var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
  336.               getService(Ci.nsIExternalProtocolService);
  337.     var handlerInfo = eps.getProtocolHandlerInfo(aProtocol);
  338.     var handlers =  handlerInfo.possibleApplicationHandlers;
  339.     for (let i = 0; i < handlers.length; i++) {
  340.       try { // We only want to test web handlers
  341.         let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp);
  342.         if (handler.uriTemplate == aURITemplate)
  343.           return true;
  344.       } catch (e) { /* it wasn't a web handler */ }
  345.     }
  346.     return false;
  347.   },
  348.  
  349.   /**
  350.    * See nsIWebContentHandlerRegistrar
  351.    */
  352.   registerProtocolHandler: 
  353.   function WCCR_registerProtocolHandler(aProtocol, aURIString, aTitle, aContentWindow) {
  354.     LOG("registerProtocolHandler(" + aProtocol + "," + aURIString + "," + aTitle + ")");
  355.     
  356.     // First, check to make sure this isn't already handled internally (we don't
  357.     // want to let them take over, say "chrome").
  358.     var ios = Cc["@mozilla.org/network/io-service;1"].
  359.               getService(Ci.nsIIOService);
  360.     var handler = ios.getProtocolHandler(aProtocol);
  361.     if (!(handler instanceof Ci.nsIExternalProtocolHandler)) {
  362.       // This is handled internally, so we don't want them to register
  363.       // XXX this should be a "security exception" according to spec, but that
  364.       // isn't defined yet.
  365.       throw("Permission denied to add " + aURIString + "as a protocol handler");
  366.     }
  367.  
  368.     var uri = this._checkAndGetURI(aURIString);
  369.  
  370.     var buttons, message;
  371.     if (this._protocolHandlerRegistered(aProtocol, uri.spec))
  372.       message = this._getFormattedString("protocolHandlerRegistered",
  373.                                          [aTitle, aProtocol]);
  374.     else {
  375.       // Now Ask the user and provide the proper callback
  376.       message = this._getFormattedString("addProtocolHandler",
  377.                                          [aTitle, uri.host, aProtocol]);
  378.       var fis = Cc["@mozilla.org/browser/favicon-service;1"].
  379.                 getService(Ci.nsIFaviconService);
  380.       var notificationIcon = fis.getFaviconLinkForIcon(uri);
  381.       var notificationValue = "Protocol Registration: " + aProtocol;
  382.       var addButton = {
  383.         label: this._getString("addProtocolHandlerAddButton"),
  384.         accessKey: this._getString("addHandlerAddButtonAccesskey"),
  385.         protocolInfo: { protocol: aProtocol, uri: uri.spec, name: aTitle },
  386.  
  387.         callback:
  388.         function WCCR_addProtocolHandlerButtonCallback(aNotification, aButtonInfo) {
  389.           var protocol = aButtonInfo.protocolInfo.protocol;
  390.           var uri      = aButtonInfo.protocolInfo.uri;
  391.           var name     = aButtonInfo.protocolInfo.name;
  392.  
  393.           var handler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
  394.                         createInstance(Ci.nsIWebHandlerApp);
  395.           handler.name = name;
  396.           handler.uriTemplate = uri;
  397.  
  398.           var eps = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
  399.                     getService(Ci.nsIExternalProtocolService);
  400.           var handlerInfo = eps.getProtocolHandlerInfo(protocol);
  401.           handlerInfo.possibleApplicationHandlers.appendElement(handler, false);
  402.  
  403.           var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
  404.                    getService(Ci.nsIHandlerService);
  405.           hs.store(handlerInfo);
  406.         }
  407.       };
  408.       buttons = [addButton];
  409.     }
  410.  
  411.     var browserWindow = this._getBrowserWindowForContentWindow(aContentWindow);
  412.     var browserElement = this._getBrowserForContentWindow(browserWindow, aContentWindow);
  413.     var notificationBox = browserWindow.getBrowser().getNotificationBox(browserElement);
  414.     notificationBox.appendNotification(message,
  415.                                        notificationValue,
  416.                                        notificationIcon,
  417.                                        notificationBox.PRIORITY_INFO_LOW,
  418.                                        buttons);
  419.   },
  420.  
  421.   /**
  422.    * See nsIWebContentHandlerRegistrar
  423.    * This is the web front end into the registration system, so a prompt to 
  424.    * confirm the registration is provided, and the result is saved to 
  425.    * preferences.
  426.    */
  427.   registerContentHandler: 
  428.   function WCCR_registerContentHandler(aContentType, aURIString, aTitle, aContentWindow) {
  429.     LOG("registerContentHandler(" + aContentType + "," + aURIString + "," + aTitle + ")");
  430.  
  431.     // We only support feed types at present.
  432.     // XXX this should be a "security exception" according to spec, but that
  433.     // isn't defined yet.
  434.     var contentType = this._resolveContentType(aContentType);
  435.     if (contentType != TYPE_MAYBE_FEED)
  436.       return;
  437.  
  438.     var uri = this._checkAndGetURI(aURIString);
  439.             
  440.     // For security reasons we reject non-http(s) urls (see bug Bug 354316),
  441.     // we may need to revise this once we support more content types
  442.     // XXX this should be a "security exception" according to spec, but that
  443.     // isn't defined yet.
  444.     if (uri.scheme != "http" &&  uri.scheme != "https")
  445.       throw("Permission denied to add " + uri.spec + "as a content handler");
  446.  
  447.     var browserWindow = this._getBrowserWindowForContentWindow(aContentWindow);
  448.     var browserElement = this._getBrowserForContentWindow(browserWindow, aContentWindow);
  449.     var notificationBox = browserWindow.getBrowser().getNotificationBox(browserElement);
  450.     this._appendFeedReaderNotification(uri, aTitle, notificationBox);
  451.   },
  452.  
  453.   /**
  454.    * Returns the browser chrome window in which the content window is in
  455.    */
  456.   _getBrowserWindowForContentWindow:
  457.   function WCCR__getBrowserWindowForContentWindow(aContentWindow) {
  458.     return aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
  459.                          .getInterface(Ci.nsIWebNavigation)
  460.                          .QueryInterface(Ci.nsIDocShellTreeItem)
  461.                          .rootTreeItem
  462.                          .QueryInterface(Ci.nsIInterfaceRequestor)
  463.                          .getInterface(Ci.nsIDOMWindow)
  464.                          .wrappedJSObject;
  465.   },
  466.  
  467.   /**
  468.    * Returns the <xul:browser> element associated with the given content
  469.    * window.
  470.    *
  471.    * @param aBrowserWindow
  472.    *        The browser window in which the content window is in.
  473.    * @param aContentWindow
  474.    *        The content window. It's possible to pass a child content window
  475.    *        (i.e. the content window of a frame/iframe).
  476.    */
  477.   _getBrowserForContentWindow:
  478.   function WCCR__getBrowserForContentWindow(aBrowserWindow, aContentWindow) {
  479.     // This depends on pseudo APIs of browser.js and tabbrowser.xml
  480.     aContentWindow = aContentWindow.top;
  481.     var browsers = aBrowserWindow.getBrowser().browsers;
  482.     for (var i = 0; i < browsers.length; ++i) {
  483.       if (browsers[i].contentWindow == aContentWindow)
  484.         return browsers[i];
  485.     }
  486.   },
  487.  
  488.   /**
  489.    * Appends a notifcation for the given feed reader details.
  490.    *
  491.    * The notification could be either a pseudo-dialog which lets
  492.    * the user to add the feed reader:
  493.    * [ [icon] Add %feed-reader-name% (%feed-reader-host%) as a Feed Reader?  (Add) [x] ]
  494.    *
  495.    * or a simple message for the case where the feed reader is already registered:
  496.    * [ [icon] %feed-reader-name% is already registered as a Feed Reader             [x] ]
  497.    *
  498.    * A new notification isn't appended if the given notificationbox has a
  499.    * notification for the same feed reader.
  500.    *
  501.    * @param aURI
  502.    *        The url of the feed reader as a nsIURI object
  503.    * @param aName
  504.    *        The feed reader name as it was passed to registerContentHandler
  505.    * @param aNotificationBox
  506.    *        The notification box to which a notification might be appended
  507.    * @return true if a notification has been appended, false otherwise.
  508.    */
  509.   _appendFeedReaderNotification:
  510.   function WCCR__appendFeedReaderNotification(aURI, aName, aNotificationBox) {
  511.     var uriSpec = aURI.spec;
  512.     var notificationValue = "feed reader notification: " + uriSpec;
  513.     var notificationIcon = aURI.prePath + "/favicon.ico";
  514.  
  515.     // Don't append a new notification if the notificationbox
  516.     // has a notification for the given feed reader already
  517.     if (aNotificationBox.getNotificationWithValue(notificationValue))
  518.       return false;
  519.  
  520.     var buttons, message;
  521.     if (this.getWebContentHandlerByURI(TYPE_MAYBE_FEED, uriSpec))
  522.       message = this._getFormattedString("handlerRegistered", [aName]);
  523.     else {
  524.       message = this._getFormattedString("addHandler", [aName, aURI.host]);
  525.       var self = this;
  526.       var addButton = {
  527.         _outer: self,
  528.         label: self._getString("addHandlerAddButton"),
  529.         accessKey: self._getString("addHandlerAddButtonAccesskey"),
  530.         feedReaderInfo: { uri: uriSpec, name: aName },
  531.  
  532.         /* static */
  533.         callback:
  534.         function WCCR__addFeedReaderButtonCallback(aNotification, aButtonInfo) {
  535.           var uri = aButtonInfo.feedReaderInfo.uri;
  536.           var name = aButtonInfo.feedReaderInfo.name;
  537.           var outer = aButtonInfo._outer;
  538.  
  539.           // The reader could have been added from another window mean while
  540.           if (!outer.getWebContentHandlerByURI(TYPE_MAYBE_FEED, uri)) {
  541.             outer._registerContentHandler(TYPE_MAYBE_FEED, uri, name);
  542.             outer._saveContentHandlerToPrefs(TYPE_MAYBE_FEED, uri, name);
  543.  
  544.             // Make the new handler the last-selected reader in the preview page
  545.             // and make sure the preview page is shown the next time a feed is visited
  546.             var pb = Cc["@mozilla.org/preferences-service;1"].
  547.                      getService(Ci.nsIPrefService).getBranch(null);
  548.             pb.setCharPref(PREF_SELECTED_READER, "web");
  549.  
  550.             var supportsString = 
  551.               Cc["@mozilla.org/supports-string;1"].
  552.               createInstance(Ci.nsISupportsString);
  553.               supportsString.data = uri;
  554.             pb.setComplexValue(PREF_SELECTED_WEB, Ci.nsISupportsString,
  555.                                supportsString);
  556.             pb.setCharPref(PREF_SELECTED_ACTION, "ask");
  557.             outer._setAutoHandler(TYPE_MAYBE_FEED, null);
  558.           }
  559.  
  560.           // avoid reference cycles
  561.           aButtonInfo._outer = null;
  562.  
  563.           return false;
  564.         }
  565.       };
  566.       buttons = [addButton];
  567.     }
  568.  
  569.     aNotificationBox.appendNotification(message,
  570.                                         notificationValue,
  571.                                         notificationIcon,
  572.                                         aNotificationBox.PRIORITY_INFO_LOW,
  573.                                         buttons);
  574.     return true;
  575.   },
  576.  
  577.   /**
  578.    * Save Web Content Handler metadata to persistent preferences. 
  579.    * @param   contentType
  580.    *          The content Type being handled
  581.    * @param   uri
  582.    *          The uri of the web service
  583.    * @param   title
  584.    *          The human readable name of the web service
  585.    *
  586.    * This data is stored under:
  587.    * 
  588.    *    browser.contentHandlers.type0 = content/type
  589.    *    browser.contentHandlers.uri0 = http://www.foo.com/q=%s
  590.    *    browser.contentHandlers.title0 = Foo 2.0alphr
  591.    */
  592.   _saveContentHandlerToPrefs: 
  593.   function WCCR__saveContentHandlerToPrefs(contentType, uri, title) {
  594.     var ps = 
  595.         Cc["@mozilla.org/preferences-service;1"].
  596.         getService(Ci.nsIPrefService);
  597.     var i = 0;
  598.     var typeBranch = null;
  599.     while (true) {
  600.       typeBranch = 
  601.         ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + i + ".");
  602.       try {
  603.         typeBranch.getCharPref("type");
  604.         ++i;
  605.       }
  606.       catch (e) {
  607.         // No more handlers
  608.         break;
  609.       }
  610.     }
  611.     if (typeBranch) {
  612.       typeBranch.setCharPref("type", contentType);
  613.       var pls = 
  614.           Cc["@mozilla.org/pref-localizedstring;1"].
  615.           createInstance(Ci.nsIPrefLocalizedString);
  616.       pls.data = uri;
  617.       typeBranch.setComplexValue("uri", Ci.nsIPrefLocalizedString, pls);
  618.       pls.data = title;
  619.       typeBranch.setComplexValue("title", Ci.nsIPrefLocalizedString, pls);
  620.     
  621.       ps.savePrefFile(null);
  622.     }
  623.   },
  624.   
  625.   /**
  626.    * Determines if there is a type with a particular uri registered for the 
  627.    * specified content type already.
  628.    * @param   contentType
  629.    *          The content type that the uri handles
  630.    * @param   uri
  631.    *          The uri of the 
  632.    */
  633.   _typeIsRegistered: function WCCR__typeIsRegistered(contentType, uri) {
  634.     if (!(contentType in this._contentTypes))
  635.       return false;
  636.       
  637.     var services = this._contentTypes[contentType];
  638.     for (var i = 0; i < services.length; ++i) {
  639.       // This uri has already been registered
  640.       if (services[i].uri == uri)
  641.         return true;
  642.     }
  643.     return false;
  644.   },
  645.   
  646.   /**
  647.    * Gets a stream converter contract id for the specified content type.
  648.    * @param   contentType
  649.    *          The source content type for the conversion.
  650.    * @returns A contract id to construct a converter to convert between the 
  651.    *          contentType and *\/*.
  652.    */
  653.   _getConverterContractID: function WCCR__getConverterContractID(contentType) {
  654.     const template = "@mozilla.org/streamconv;1?from=%s&to=*/*";
  655.     return template.replace(/%s/, contentType);
  656.   },
  657.   
  658.   /**
  659.    * Update the content type -> handler map. This mapping is not persisted, use
  660.    * registerContentHandler or _saveContentHandlerToPrefs for that purpose.
  661.    * @param   contentType
  662.    *          The content Type being handled
  663.    * @param   uri
  664.    *          The uri of the web service
  665.    * @param   title
  666.    *          The human readable name of the web service
  667.    */
  668.   _registerContentHandler: 
  669.   function WCCR__registerContentHandler(contentType, uri, title) {
  670.     if (!(contentType in this._contentTypes))
  671.       this._contentTypes[contentType] = [];
  672.  
  673.     // Avoid adding duplicates
  674.     if (this._typeIsRegistered(contentType, uri)) 
  675.       return;
  676.     
  677.     this._contentTypes[contentType].push(new ServiceInfo(contentType, uri, title));
  678.     
  679.     if (!(contentType in this._blockedTypes)) {
  680.       var converterContractID = this._getConverterContractID(contentType);
  681.       var cr = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
  682.       cr.registerFactory(WCC_CLASSID, WCC_CLASSNAME, converterContractID, 
  683.                          WebContentConverterFactory);
  684.     }
  685.   },
  686.   
  687.   /**
  688.    * See nsIWebContentConverterService
  689.    */
  690.   getContentHandlers: 
  691.   function WCCR_getContentHandlers(contentType, countRef) {
  692.     countRef.value = 0;
  693.     if (!(contentType in this._contentTypes))
  694.       return [];
  695.     
  696.     var handlers = this._contentTypes[contentType];
  697.     countRef.value = handlers.length;
  698.     return handlers;
  699.   },
  700.   
  701.   /**
  702.    * See nsIWebContentConverterService
  703.    */
  704.   resetHandlersForType: 
  705.   function WCCR_resetHandlersForType(contentType) {
  706.     // currently unused within the tree, so only useful for extensions; previous
  707.     // impl. was buggy (and even infinite-looped!), so I argue that this is a
  708.     // definite improvement
  709.     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  710.   },
  711.   
  712.   /**
  713.    * Registers a handler from the settings on a preferences branch.
  714.    *
  715.    * @param branch
  716.    *        an nsIPrefBranch containing "type", "uri", and "title" preferences
  717.    *        corresponding to the content handler to be registered
  718.    */
  719.   _registerContentHandlerWithBranch: function(branch) {
  720.     /**
  721.      * Since we support up to six predefined readers, we need to handle gaps 
  722.      * better, since the first branch with user-added values will be .6
  723.      * 
  724.      * How we deal with that is to check to see if there's no prefs in the 
  725.      * branch and stop cycling once that's true.  This doesn't fix the case
  726.      * where a user manually removes a reader, but that's not supported yet!
  727.      */
  728.     var vals = branch.getChildList("", {});
  729.     if (vals.length == 0)
  730.       return;
  731.  
  732.     try {
  733.       var type = branch.getCharPref("type");
  734.       var uri = branch.getComplexValue("uri", Ci.nsIPrefLocalizedString).data;
  735.       var title = branch.getComplexValue("title",
  736.                                          Ci.nsIPrefLocalizedString).data;
  737.       this._registerContentHandler(type, uri, title);
  738.     }
  739.     catch(ex) {
  740.       // do nothing, the next branch might have values
  741.     }
  742.   },
  743.  
  744.   /**
  745.    * Load the auto handler, content handler and protocol tables from 
  746.    * preferences.
  747.    */
  748.   _init: function WCCR__init() {
  749.     var ps = 
  750.         Cc["@mozilla.org/preferences-service;1"].
  751.         getService(Ci.nsIPrefService);
  752.  
  753.     var kids = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH)
  754.                  .getChildList("", {});
  755.  
  756.     // first get the numbers of the providers by getting all ###.uri prefs
  757.     var nums = [];
  758.     for (var i = 0; i < kids.length; i++) {
  759.       var match = /^(\d+)\.uri$/.exec(kids[i]);
  760.       if (!match)
  761.         continue;
  762.       else
  763.         nums.push(match[1]);
  764.     }
  765.  
  766.     // now register them
  767.     for (var i = 0; i < nums.length; i++) {
  768.       var branch = ps.getBranch(PREF_CONTENTHANDLERS_BRANCH + nums[i] + ".");
  769.       this._registerContentHandlerWithBranch(branch);
  770.     }
  771.  
  772.     // We need to do this _after_ registering all of the available handlers, 
  773.     // so that getWebContentHandlerByURI can return successfully.
  774.     try {
  775.       var autoBranch = ps.getBranch(PREF_CONTENTHANDLERS_AUTO);
  776.       var childPrefs = autoBranch.getChildList("", { });
  777.       for (var i = 0; i < childPrefs.length; ++i) {
  778.         var type = childPrefs[i];
  779.         var uri = autoBranch.getCharPref(type);
  780.         if (uri) {
  781.           var handler = this.getWebContentHandlerByURI(type, uri);
  782.           this._setAutoHandler(type, handler);
  783.         }
  784.       }
  785.     }
  786.     catch (e) {
  787.       // No auto branch yet, that's fine
  788.       //LOG("WCCR.init: There is no auto branch, benign");
  789.     }
  790.   },
  791.  
  792.   /**
  793.    * See nsIObserver
  794.    */
  795.   observe: function WCCR_observe(subject, topic, data) {
  796.     var os = 
  797.         Cc["@mozilla.org/observer-service;1"].
  798.         getService(Ci.nsIObserverService);
  799.     switch (topic) {
  800.     case "app-startup":
  801.       os.addObserver(this, "profile-after-change", false);
  802.       os.addObserver(this, "xpcom-shutdown", false);
  803.       break;
  804.     case "profile-after-change":
  805.       os.removeObserver(this, "profile-after-change");
  806.       this._init();
  807.       break;
  808.     case "xpcom-shutdown":
  809.       this.classID = null;
  810.     }
  811.   },
  812.   
  813.   /**
  814.    * See nsIFactory
  815.    */
  816.   createInstance: function WCCR_createInstance(outer, iid) {
  817.     if (outer != null)
  818.       throw Cr.NS_ERROR_NO_AGGREGATION;
  819.     return this.QueryInterface(iid);
  820.   },
  821.  
  822.   /**
  823.    * See nsIClassInfo
  824.    */
  825.   getInterfaces: function WCCR_getInterfaces(countRef) {
  826.     var interfaces = 
  827.         [Ci.nsIWebContentConverterService, Ci.nsIWebContentHandlerRegistrar,
  828.          Ci.nsIObserver, Ci.nsIClassInfo, Ci.nsIFactory, Ci.nsISupports];
  829.     countRef.value = interfaces.length;
  830.     return interfaces;
  831.   },
  832.   getHelperForLanguage: function WCCR_getHelperForLanguage(language) {
  833.     return null;
  834.   },
  835.   contractID: WCCR_CONTRACTID,
  836.   classDescription: WCCR_CLASSNAME,
  837.   classID: WCCR_CLASSID,
  838.   implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
  839.   flags: Ci.nsIClassInfo.DOM_OBJECT,
  840.   
  841.   /**
  842.    * See nsISupports
  843.    */
  844.   QueryInterface: function WCCR_QueryInterface(iid) {
  845.     if (iid.equals(Ci.nsIWebContentConverterService) || 
  846.         iid.equals(Ci.nsIWebContentHandlerRegistrar) ||
  847.         iid.equals(Ci.nsIObserver) ||
  848.         iid.equals(Ci.nsIClassInfo) ||
  849.         iid.equals(Ci.nsIFactory) ||
  850.         iid.equals(Ci.nsISupports))
  851.       return this;
  852.     throw Cr.NS_ERROR_NO_INTERFACE;
  853.   },
  854. };
  855.  
  856. var Module = {
  857.   QueryInterface: function M_QueryInterface(iid) {
  858.     if (iid.equals(Ci.nsIModule) ||
  859.         iid.equals(Ci.nsISupports))
  860.       return this;
  861.     throw Cr.NS_ERROR_NO_INTERFACE;
  862.   },
  863.   
  864.   getClassObject: function M_getClassObject(cm, cid, iid) {
  865.     if (!iid.equals(Ci.nsIFactory))
  866.       throw Cr.NS_ERROR_NOT_IMPLEMENTED;
  867.     
  868.     if (cid.equals(WCCR_CLASSID))
  869.       return WebContentConverterRegistrar;
  870.       
  871.     throw Cr.NS_ERROR_NO_INTERFACE;
  872.   },
  873.   
  874.   registerSelf: function M_registerSelf(cm, file, location, type) {
  875.     var cr = cm.QueryInterface(Ci.nsIComponentRegistrar);
  876.     cr.registerFactoryLocation(WCCR_CLASSID, WCCR_CLASSNAME, WCCR_CONTRACTID,
  877.                                file, location, type);
  878.  
  879.     var catman = 
  880.         Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
  881.     catman.addCategoryEntry("app-startup", WCCR_CLASSNAME, 
  882.                             "service," + WCCR_CONTRACTID, true, true);
  883.   },
  884.   
  885.   unregisterSelf: function M_unregisterSelf(cm, location, type) {
  886.     var cr = cm.QueryInterface(Ci.nsIComponentRegistrar);
  887.     cr.unregisterFactoryLocation(WCCR_CLASSID, location);
  888.   },
  889.   
  890.   canUnload: function M_canUnload(cm) {
  891.     return true;
  892.   }
  893. };
  894.  
  895. function NSGetModule(cm, file) {
  896.   return Module;
  897. }
  898.  
  899. //@line 44 "e:\builds\tinderbox\Fx-Rel\WINNT_5.2_Depend\mozilla\toolkit\content\debug.js"
  900.  
  901. var gTraceOnAssert = true;
  902.  
  903. /**
  904.  * This function provides a simple assertion function for JavaScript.
  905.  * If the condition is true, this function will do nothing.  If the
  906.  * condition is false, then the message will be printed to the console
  907.  * and an alert will appear showing a stack trace, so that the (alpha
  908.  * or nightly) user can file a bug containing it.  For future enhancements, 
  909.  * see bugs 330077 and 330078.
  910.  *
  911.  * To suppress the dialogs, you can run with the environment variable
  912.  * XUL_ASSERT_PROMPT set to 0 (if unset, this defaults to 1).
  913.  *
  914.  * @param condition represents the condition that we're asserting to be
  915.  *                  true when we call this function--should be
  916.  *                  something that can be evaluated as a boolean.
  917.  * @param message   a string to be displayed upon failure of the assertion
  918.  */
  919.  
  920. function NS_ASSERT(condition, message) {
  921.   if (condition)
  922.     return;
  923.  
  924.   var releaseBuild = true;
  925.   var defB = Components.classes["@mozilla.org/preferences-service;1"]
  926.                        .getService(Components.interfaces.nsIPrefService)
  927.                        .getDefaultBranch(null);
  928.   try {
  929.     switch (defB.getCharPref("app.update.channel")) {
  930.       case "nightly":
  931.       case "beta":
  932.       case "default":
  933.         releaseBuild = false;
  934.     }
  935.   } catch(ex) {}
  936.  
  937.   var caller = arguments.callee.caller;
  938.   var assertionText = "ASSERT: " + message + "\n";
  939.  
  940.   if (releaseBuild) {
  941.     // Just report the error to the console
  942.     Components.utils.reportError(assertionText);
  943.     return;
  944.   }
  945.  
  946.   // Otherwise, dump to stdout and launch an assertion failure dialog
  947.   dump(assertionText);
  948.  
  949.   var stackText = "";
  950.   if (gTraceOnAssert) {
  951.     stackText = "Stack Trace: \n";
  952.     var count = 0;
  953.     while (caller) {
  954.       stackText += count++ + ":" + caller.name + "(";
  955.       for (var i = 0; i < caller.arguments.length; ++i) {
  956.         var arg = caller.arguments[i];
  957.         stackText += arg;
  958.         if (i < caller.arguments.length - 1)
  959.           stackText += ",";
  960.       }
  961.       stackText += ")\n";
  962.       caller = caller.arguments.callee.caller;
  963.     }
  964.   }
  965.  
  966.   var environment = Components.classes["@mozilla.org/process/environment;1"].
  967.                     getService(Components.interfaces.nsIEnvironment);
  968.   if (environment.exists("XUL_ASSERT_PROMPT") &&
  969.       !parseInt(environment.get("XUL_ASSERT_PROMPT")))
  970.     return;
  971.  
  972.   var source = null;
  973.   if (this.window)
  974.     source = window;
  975.   var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
  976.            getService(Components.interfaces.nsIPromptService);
  977.   ps.alert(source, "Assertion Failed", assertionText + stackText);
  978. }
  979. //@line 936 "e:\builds\tinderbox\Fx-Rel\WINNT_5.2_Depend\mozilla\browser\components\feeds\src\WebContentConverter.js"
  980.  
  981.